﻿using System;
using System.Collections.Generic;
using Swift.Math;

namespace Swift
{
    /// <summary>
    /// Math related Utils
    /// </summary>
    public static class MU
    {
        // 截断 (min, max)
        public static int ClampLR(this int v, int min, int max)
        {
            return v.Clamp(min + 1, max - 1);
        }

        // 截断 (min, max]
        public static int ClampR(this int v, int min, int max)
        {
            return v.Clamp(min + 1, max);
        }

        // 截断 [min, max)
        public static int ClampL(this int v, int min, int max)
        {
            return v.Clamp(min, max - 1);
        }

        // 截断 [min, max]
        public static int Clamp(this int v, int min, int max)
        {
            if (v < min)
                return min;
            else if (v > max)
                return max;
            else
                return v;
        }

        public static int SetMin(this int v, int min)
        {
            if (v < min)
                return min;
            else
                return v;
        }

        // 根据给定向量方向计算对应角度
        public static Fix64 v2Degree(Fix64 y, Fix64 x)
        {
            var arc = Fix64.Atan2(y, x);
            return arc * 180 / Fix64.Pi;
        }

        // 判断给定扇形是否与指定圆形相交
        public static bool IsFunOverlappedCircle(Vec2 circleCenter, Fix64 circleR, Vec2 fanCenter, Fix64 fanR, Fix64 fanDir, Fix64 fanAngle)
        {
            // 先判断圆心距离
            var dc = circleCenter - fanCenter;
            var r = dc.Length;
            if (r > circleR + fanR)
                return false;

            // 在判断方向角度
            var dir = MU.v2Degree(dc.x, dc.y);
            var dd = (dir - fanDir).RangeIn180();
            return Fix64.Abs(dd) <= fanAngle / 2;
        }

        // 对给定的 Vec2 在指定范围内做镜像
        public static void MirroClamp(this Vec2 v, Vec2 min, Vec2 max)
        {
            if (v.x < min.x)
                v.x = 2 * min.x - v.x;
            else if (v.x > max.x)
                v.x = 2 * max.x - v.x;

            if (v.y < min.y)
                v.y = 2 * min.y - v.y;
            else if (v.y > max.y)
                v.y = 2 * max.y - v.y;
        }

        // 对给定的 Vec2 在指定范围内做镜像
        public static void MirroClamp(this Vec2 v, Vec2 max)
        {
            v.MirroClamp(Vec2.Zero, max);
        }

        // 判断给定左边是否在指定矩形范围内
        public static bool InRect(this Vec2 v, Vec2 min, Vec2 max)
        {
            return InRect(v.x, v.y, min.x, min.y, max.x - min.x + 1, max.y - min.y + 1);
        }

        // 判断给定左边是否在指定矩形范围内
        public static bool InRect(this Vec2 v, Vec2 max)
        {
            return v.InRect(Vec2.Zero, max);
        }

        // 判断给定左边是否在指定矩形范围内
        public static bool InRect(Fix64 x, Fix64 y, Fix64 left, Fix64 top, Fix64 width, Fix64 height)
        {
            return x >= left && x <= x + width - 1 && y >= top && y <= top + height - 1;
        }

        // 计算曼哈顿距离
        public static int ManhattanDist(int v1x, int v1y, int v2x, int v2y) { return (int)ManhattanDist(new Vec2(v1x, v1y), new Vec2(v2x, v2y)); }
        public static Fix64 ManhattanDist(Vec2 v1, Vec2 v2)
        {
            return MathEx.Abs(v1.x - v2.x) + MathEx.Abs(v1.y - v2.y);
        }

        // 数组全排列，从长到短
        public static void FullPermuation<T>(this T[] fullArr, Action<T[]> onSubArr, Func<bool> continueCondition = null)
        {
            var q = new Queue<T[]>();
            q.Enqueue(fullArr);

            while (q.Count > 0 && (continueCondition == null || continueCondition()))
            {
                var arr = q.Peek();
                q.Dequeue();
                onSubArr(arr);

                for (var i = 0; i < arr.Length; i++)
                {
                    var subArr1 = arr.SubArray(0, i);
                    var subArr2 = arr.SubArray(i + 1, arr.Length - i - 1);
                    var lst = new List<T>();
                    lst.AddRange(subArr1);
                    lst.AddRange(subArr2);
                    var subArr = lst.ToArray();
                    q.Enqueue(subArr);
                }
            }
        }
    }
}